#ifndef NesPPU_H_INCLUDED
#define NesPPU_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>


/* PAL分辨率 */
#define PPU_X_MAX_PIXEL  256
#define PPU_Y_MAX_PIXEL  240


#define PPUCTRL_ADDR   0x2000
#define PPUMASK_ADDR   0x2001
#define PPUSTATUS_ADDR 0x2002
#define OAMADDR_ADDR   0x2003
#define OAMDATA_ADDR   0x2004
#define PPUSCROLL_ADDR 0x2005
#define PPUADDR_ADDR   0x2006
#define PPUDATA_ADDR   0x2007
#define OAMDMA_ADDR    0x4014

/* 与CPU通信的寄存器 */
typedef struct{
    uint32_t PPUCTRL;
    uint32_t PPUMASK;
    uint32_t PPUSTATUS;
    uint32_t OAMADDR;
    uint32_t OAMDATA;
    uint32_t PPUSCROLL;
    uint32_t PPUADDR;
    uint32_t PPUDATA;
    uint32_t OAMDMA;
}NesPPURegisterType;

/* OAM RAM内存 精灵属性表 */
typedef struct{
    uint8_t coordY;
    uint8_t titleNumber;
    uint8_t attribute;
    uint8_t coordX;
}NesPPUSpiritInfoType;

typedef struct{
    uint32_t fineY;
    uint32_t fineX;
    uint32_t nametable;
}NesPPURegisterInsideType;

/*
  0000h-0FFFh   Pattern Table 0 (4K) (256 Tiles)
  1000h-1FFFh   Pattern Table 1 (4K) (256 Tiles)
  2000h-23FFh   Name Table 0 and Attribute Table 0 (1K) (32x30 BG Map)
  2400h-27FFh   Name Table 1 and Attribute Table 1 (1K) (32x30 BG Map)
  2800h-2BFFh   Name Table 2 and Attribute Table 2 (1K) (32x30 BG Map)
  2C00h-2FFFh   Name Table 3 and Attribute Table 3 (1K) (32x30 BG Map)
  3000h-3EFFh   Mirror of 2000h-2EFFh
  3F00h-3F1Fh   Background and Sprite Palettes (25 entries used)
  3F20h-3FFFh   Mirrors of 3F00h-3F1Fh
*/
typedef struct{
    /* 图像表 bank0 */
    uint8_t *PatternTablesBank0;
    /* 图像表 bank1 */
    uint8_t *PatternTablesBank1;
    /* 名称表 */
    uint8_t *NameTables;
    /* 背景颜色表 */
    uint8_t *ColorBackground;
    /* 精灵颜色表 */
    uint8_t *ColorSprite;
    /* OAM RAM 当前读写地址 */
    uint8_t *OamAddr;

    /* 与CPU通信的寄存器 */
    NesPPURegisterType registers;

    /* PPU内存写入时，地址自增步进长度 */
    uint32_t addrIncrement;

    /* 当前扫描点的X轴 */
    uint32_t pointNowX;
    /* 当前扫描点的Y轴 */
    uint32_t pointNowY;

    /* PPU已运行时钟数 */
    int64_t clockCnt;
    /* PPU已刷新的帧数 */
    int64_t frameCnt;

    /* PPU内部寄存器 */
    NesPPURegisterInsideType t;
    NesPPURegisterInsideType v;
    uint32_t w;
}NesPPUInofType;





uint32_t cNesPPUBankAddr4kByteSet(uint32_t cSerial, uint32_t uiAddr);
uint32_t cNesPPUBankAddr8kByteSet(uint32_t uiAddr);
void vNesPPUMemoryLoad(uint32_t cSerial, uint32_t uiAddr, int32_t iLength);
void vNesPPUOamRamSet(uint32_t ucAddr, uint8_t *pucBuff, uint32_t iLength);

uint32_t ucNesPPURegisterGet(uint32_t addr);
void vNesPPURegisterSet(uint32_t addr, uint32_t value);

void vNesPPUStart(void);
void vNesPPUInit(void);
uint32_t cNesPPULineScanf(void);
void vNesPPUExec(void);

NesPPUInofType *ptyeNesPPUInfoGet(void);


#ifdef __cplusplus
}
#endif

#endif // NesPPU_H_INCLUDED
